/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       skill_choice_dialog.cpp

	$Header: /game/skill_choice_dialog.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "skill_choice_dialog.h"

#include "adaptor_handler.h"
#include "adventure_sounds.h"
#include "bitmap_group_cache.h"
#include "bitmap_layer_cache_window.h"
#include "bitmap_layer_window.h"
#include "bound_handler.h"
#include "button_cache.h"
#include "creature_ability.h"
#include "enum_operations.h"
#include "external_string.h"
#include "format_string.h"
#include "game_replace_keywords.h"
#include "get_artifact_damage_modifier.h"
#include "hero.h"
#include "hero_class_properties.h"
#include "interface_help.h"
#include "item_help_block.h"
#include "replace_keywords.h"
#include "skill_button.h"
#include "skill_icon.h"
#include "skill_properties.h"
#include "standard_fonts.h"
#include "text_window.h"

static t_bitmap_group_cache const k_bitmaps( "dialog.choose_skill" );
extern t_button_cache			  g_ok_button;

static t_external_string const k_text_choose_skill( "skill_choice_choose_skill.misc" );
static t_external_string const k_text_new_class( "skill_choice_new_class.misc" );
// -------------------------------------------------------------------
// dialog to choose a skill for a hero
// -------------------------------------------------------------------
t_skill_choice_dialog::t_skill_choice_dialog( t_hero& hero, t_window* parent, t_adventure_map const & map )
                     : t_window( k_completely_transparent, parent ), m_hero( hero )
{
	t_screen_rect         rect;
	t_bitmap_layer const* layer;
	t_window*             window;
	t_window*             background;
	t_screen_point        origin(0,0);


	get_dialog_sound( k_dialog_sound_level_up )->play( get_sound_volume() );

	m_bitmaps = k_bitmaps.get();
	m_skills = hero.get_skill_choices( map );

	// create background
	layer = m_bitmaps->find( "top" );
	window = new t_bitmap_layer_window( layer, origin, this );
	layer = m_bitmaps->find( "left" );
	window = new t_bitmap_layer_window( layer, origin, this );
	layer = m_bitmaps->find( "bottom" );
	window = new t_bitmap_layer_window( layer, origin, this );
	layer = m_bitmaps->find( "right" );
	window = new t_bitmap_layer_window( layer, origin, this );

	layer = m_bitmaps->find( "background" );
	background = new t_bitmap_layer_window( layer, origin, this );
	origin = -layer->get_rect().top_left();

	// create portrait
	layer = m_bitmaps->find( "hero_portrait" );
	rect = layer->get_rect() + origin;
	window = new t_bitmap_layer_cache_window( hero.get_portrait( rect.height() ),
		                                      rect.top_left(), background, false );
	window->set_help_balloon_text( hero.get_name() );
	// create frame for portrait
	layer = m_bitmaps->find( "portrait_frame" );
	window = new t_bitmap_layer_window( layer, origin, background );

	// create hero name
	t_text_window* text_window;

	rect = m_bitmaps->find( "hero_name" )->get_rect() + origin;
	text_window = new t_text_window( get_font( rect.height() ), rect, background,
								     hero.get_name(), t_pixel_24(0,0,0) );
	text_window->set_drop_shadow( false );
	text_window->set_center_horizontal();

	rect = m_bitmaps->find( "dialog_text" )->get_rect() + origin;
	text_window = new t_text_window( get_font( rect.height() ), rect, background,
		                             k_text_choose_skill, t_pixel_24(0,0,0));
	text_window->set_drop_shadow( false );
	text_window->set_center_horizontal();

	// create new class text
	rect = m_bitmaps->find("new_level_text" )->get_rect() + origin;
	m_class_text = new t_text_window( get_font( rect.height() / 2 ), rect, background,
									  "", t_pixel_24(0,0,0) );
	m_class_text->set_drop_shadow( false );
	m_class_text->set_center_horizontal();

	t_help_block const&   shared_help = get_help_block( "shared" );

	// create damage icon
	layer = m_bitmaps->find( "damage_icon" );
	window = new t_bitmap_layer_window( layer, origin, background );
	set_help( window, shared_help, "damage" );

	// create damage text
	//int lines = 1;
	int font_size = 20;

	rect = m_bitmaps->find( "damage_text" )->get_rect() + origin;
	m_damage_text = new t_text_window( get_font( font_size ), rect, background,
									   "", t_pixel_24(0,0,0) );
	m_damage_text->set_drop_shadow( false );
	m_damage_text->set_center_horizontal();
	m_damage_text->set_center_vertical();

	// create health text
	layer = m_bitmaps->find( "hit_point_icon" );
	window = new t_bitmap_layer_window( layer, origin, background );
	set_help( window, shared_help, "hit_points" );

	rect = m_bitmaps->find( "hit_point_text" )->get_rect() + origin;
	m_hit_points_text = new t_text_window( get_font( font_size ), rect, background,
										   "", t_pixel_24(0,0,0));
	m_hit_points_text->set_drop_shadow( false );
	m_hit_points_text->set_center_horizontal();
	m_hit_points_text->set_center_vertical();

	// create skill icons
	int column_x[k_skill_columns];
	int row_y[k_skill_rows];
	int row;
	int column;

	rect = m_bitmaps->find( "skill_1" )->get_rect() + origin;
	row_y[0] = rect.top;
	for (column = 0; column < k_skill_columns; ++column)
		column_x[column] = m_bitmaps->find( format_string( "skill_%i", 
		                                    column + 1 ) )->get_rect().left + origin.x;
	for (row = 1; row < k_skill_rows; ++row)
		row_y[row] = m_bitmaps->find( format_string( "row_%i", row + 1 ) )->get_rect().top 
		             + origin.y;

	for (row = 0; row < k_skill_rows; ++row)
	{
		for (column = 0; column < k_skill_columns; ++column)
		{
			rect += t_screen_point( column_x[column], row_y[row] ) - rect.top_left();
			m_skill_icons[row][column] = new t_skill_icon( rect, background );
		}
	}

	// create frame for skill icons
	layer = m_bitmaps->find( "current_skills_frame" );
	window = new t_bitmap_layer_window( layer, origin, background );

	// create selection highlight
	layer = m_bitmaps->find( "skill_location_highlight" );
	m_selection_frame = new t_bitmap_layer_window( layer, origin, background );

	// create toggle buttons
	int					  i;
	std::string			  layer_name;
	t_toggle_button*      toggle_button;
	t_screen_rect         frame_rect;
	t_screen_point        icon_offset;
	t_button_handler	  handler;
	t_bitmap_layer const* text_background;
	t_screen_point		  text_background_origin;
	t_screen_rect		  text_rect;

	text_background = m_bitmaps->find( "text_scroll" );
	text_background_origin = -m_bitmaps->find( "frame_1_of_3" )->get_rect().top_left();
	text_rect = m_bitmaps->find( "skill_text")->get_rect() + text_background_origin;
	m_skill_frame = k_skill_frames.get();
	for (i = 0; i < m_skills.size(); i++)
	{
		layer_name = format_string( "frame_%i_of_%i", i + 1, m_skills.size() );
		rect = m_bitmaps->find( layer_name )->get_rect() + origin;
		// create caption
		window = new t_bitmap_layer_window( text_background, rect.top_left()
			                                + text_background_origin, background );
		text_window = new t_text_window( get_font( text_rect.height() / 2 ),
										 text_rect + rect.top_left(), background, 
										 get_name( m_skills[i] ), t_pixel_24(0,0,0));
		text_window->set_drop_shadow( false );
		text_window->set_center_horizontal();
		text_window->set_center_vertical();

		// create button
		toggle_button = new t_toggle_button( rect.top_left(), background, true );
		create_skill_button( toggle_button, m_skills[i], m_skill_frame );
		handler = add_2nd_argument( bound_handler( *this, 
			                        &t_skill_choice_dialog::choose_skill ), i );
		toggle_button->set_click_handler( handler );
		m_button_group.add( toggle_button );
	}
	m_button_group.select( 0 );
	if (m_skills.empty())
		set_skill( t_skill( k_skill_none, k_mastery_none ));

	// add OK button
	t_button* button;

	rect = m_bitmaps->find( "ok_button" )->get_rect();
	button = new t_button( g_ok_button.get(), rect.top_left(), this );
	button->set_click_handler( bound_handler(*this, &t_skill_choice_dialog::close_click ) );
  set_help( button, shared_help, "accept" );

	t_screen_rect parent_rect = get_parent()->get_client_rect();

	rect = m_bitmaps->get_rect();
	rect += t_screen_point( parent_rect.width() - rect.width(),
		                    parent_rect.height() - rect.height() ) / 2;
	init( rect );
}

// -------------------------------------------------------------------
// dialog to choose a skill for a hero
// -------------------------------------------------------------------
void t_skill_choice_dialog::close_click( t_button* button )
{
	close();
}

// -----------------------------------------------------------------------
// dialog to manipulate one or two armies
// setup skill icons for a hero
// -----------------------------------------------------------------------
void t_skill_choice_dialog::set_skill_icons( t_skill_mastery const* skill_level )
{
	int				row_count;
	int				row;
	int				column;
	t_skill_type	skill;
	t_skill_mastery level;
	t_skill_type	primary_skill;
	int				skill_row[k_skill_primary_count];
	int				columns[k_skill_rows];
	t_skill_icon*   skill_icon;

	memset( columns, 0, sizeof(columns ));
	for (skill = t_skill_type(0); skill < k_skill_primary_count; enum_incr( skill ))
	{
		skill_row[skill] = -1;
	}

	row_count = 0;
	for (skill = t_skill_type(0); skill < k_skill_count; enum_incr( skill ))
	{
		level = skill_level[ skill ];
		if (level == k_mastery_none)
			continue;

		primary_skill = get_primary_skill( skill );
		if (skill_row[primary_skill] == -1)
		{
			if (row_count == k_skill_rows)
				continue;
			columns[row_count] = 0;
			skill_row[primary_skill] = row_count++;
		}
		row = skill_row[primary_skill];
		column = columns[row]++;
		if (column >= k_skill_columns)
			continue;
		skill_icon = m_skill_icons[row][column];
		skill_icon->set_skill( t_skill( skill, level ) );
		skill_icon->set_visible( true );
		if (skill == m_choice.skill)
		{
			t_screen_point point = skill_icon->get_screen_rect().top_left();

			point = skill_icon->to_parent( point );
			point += m_bitmaps->find( "skill_location_highlight" )->get_rect().top_left();
			point -= m_bitmaps->find( "skill_1" )->get_rect().top_left();
			m_selection_frame->move( point );
		}
	}

	for (row = 0; row < k_skill_rows; row++)
	{
		for (column = columns[row]; column < k_skill_columns; column++)
		{
			m_skill_icons[row][column]->set_visible( false );
		}
	}
}

// -------------------------------------------------------------------
// dialog to choose a skill for a hero
// -------------------------------------------------------------------
void t_skill_choice_dialog::set_skill( t_skill const& skill )
{
	std::vector<t_skill> skills;
	t_skill_mastery		 skill_level[k_skill_type_count];
	t_skill_type		 skill_type;
	
	m_choice = skill;
	for (skill_type = t_skill_type(0); skill_type < k_skill_type_count; enum_incr( skill_type ))
		skill_level[skill_type] = m_hero.get_skill( skill_type );
	if (skill.skill == k_skill_none)
		m_selection_frame->set_visible( false );
	else
		skill_level[skill.skill] = skill.level;
	for (skill_type = t_skill_type(0); skill_type < k_skill_type_count; enum_incr( skill_type ))
		if (skill_level[skill_type] > k_mastery_none)
			skills.push_back( t_skill( skill_type, skill_level[skill_type] ));

	t_hero_class new_class = m_hero.get_class();
	t_hero_class best_class = get_best_class( skills );

	if (best_class != new_class && best_class >= k_hero_class_basic_count)
	{
		int current_weight = get_class_weight( new_class, skills );
		int best_weight    = get_class_weight( best_class, skills );

		if (best_weight > current_weight)
			new_class = best_class;
	}

	std::string text;
	int			level = m_hero.get_level() + 1;

	text = k_text_new_class;
	text = replace_keywords( text, "%hero_name", m_hero.get_name(),
		                     "%level", format_string( "%i", m_hero.get_level() + 1 ),
							 "%hero_class", get_class_name( new_class ) );
	m_class_text->set_text( text );
	
	text = get_class_description( new_class );
	text = replace_keywords( text, &m_hero );
	m_class_text->set_right_click_text( text );

	// set damage text
	int low;
	int high;
	int lines = 1;
	int height;
	int artifact_damage = get_artifact_damage( m_hero, false );

	low = m_hero.get_damage_low( level ) + artifact_damage;
	high = m_hero.get_damage_high( level ) + artifact_damage;
	text = format_string( "%i-%i", low, high );
	height = 20; //m_damage_text->get_client_rect().height() / lines;
	m_damage_text->set_font( get_font( height ) );
	m_damage_text->set_text( text );

	// set health text
	int hits;

	hits = m_hero.get_hit_points( level );
	text = format_string( "%i", hits );
	m_hit_points_text->set_text( text );

	// show skills
	set_skill_icons( skill_level );
}

// -------------------------------------------------------------------
// dialog to choose a skill for a hero
// -------------------------------------------------------------------
void t_skill_choice_dialog::choose_skill( t_button* button, int id )
{
	if (button->is_pressed())
		set_skill( m_skills[id] );
}

